#ifndef SWITCHINGSINGLESUNITTESTS_H
#define SWITCHINGSINGLESUNITTESTS_H

#include "stdafx.h"
#include "TestUtils.h"
#include "SwitchVerticesAlgorithm.h"
#include "SwitchVerticesAlgorithmUnitTests.h"
#include "Helpers.h"
#include <cstdlib>

void PutVertexInGroup(bool* vertexNameInts, Graph *graph, Group *group, int n)
{
	VertexKey vertexName = Vertex::GetNameFromArray(vertexNameInts,n);
	Vertex *vertex = VertexDirectory::GetStaticCopyVertex(vertexName);
	graph->RemoveVertex(vertex);
	group->InsertNewVertex(vertex);
}

// Create a graph and a chain with no groups and try to create a new group
TestUtils::TestResult FillEmptyChain()
{
	Graph graph;
	graph = TestUtils::CreateGraph4On2(graph);

	Chain *chain = new Chain(&graph,NULL);

	Group *group0 = new Group(0,NULL);
	chain->AddGroup(group0);
	SwitchVerticesAlgorithm algo = SwitchVerticesAlgorithm(chain);

	Chain *newChain = algo.SwitchSingles();
	map<vector<bool>, Vertex*>* vertices = VertexDirectory::GetStaticCopyVertices();
	set<int> groupNames = newChain->ChainGroupNames();
	if (TestUtils::VerifyIsTrue(groupNames.size() ==1,"The group count is incorrect") == TestUtils::TestFailed)
	{
		delete newChain;
		return TestUtils::TestFailed;
	}

	Group *group = newChain->GetGroup((*groupNames.begin()));

	// check that the directory was updated correctly: All vertices in the graph appear in the graph. All vertices
	// in the group point to the right group.
	if (Algorithms::ValidateVertexDirectoryState(newChain->GetGraph(), group) == false)
	{
		delete newChain;
		return TestUtils::TestFailed;
	}

	if (Algorithms::ValidateAllGroupsAreIndependent(newChain) == false)
	{
		delete newChain;
		return TestUtils::TestFailed;
	}

	delete newChain;
	return TestUtils::TestPassed;
}

// Create a graph and a chain with 1 group with 1 vertex in in and try to create a new group
TestUtils::TestResult FillOneGroupOneVertexWithSwitching()
{
	Graph graph;
	graph = TestUtils::CreateGraph4On2(graph);
	Group group1(1);
	Group group2(2);
	bool vertexInts[] =  {0,0,1,1};
	VertexKey vertexName = Vertex::GetNameFromArray(vertexInts,4);
	Vertex *vertex = VertexDirectory::GetStaticCopyVertex(vertexName);
	graph.RemoveVertex(vertex);
	group1.InsertNewVertex(vertex);

	Chain *chain = new Chain(&graph,NULL);
	chain->AddGroup(&group1);
	chain->AddGroup(&group2);

	SwitchVerticesAlgorithm algo = SwitchVerticesAlgorithm(chain);

	Chain *newChain = algo.SwitchSingles();
	map<vector<bool>, Vertex*>* vertices = VertexDirectory::GetStaticCopyVertices();
	set<int> groupNames = newChain->ChainGroupNames();
	if (TestUtils::VerifyIsTrue(groupNames.size() ==2 ,"The group count is incorrect") == TestUtils::TestFailed)
	{
		delete newChain;
		return TestUtils::TestFailed;
	}

	Group *group = newChain->GetGroup((*groupNames.begin()));


	// check that the directory was updated correctly: All vertices in the graph appear in the graph. All vertices
	// in the group point to the right group.
	if (Algorithms::ValidateVertexDirectoryState(newChain->GetGraph(), newChain->ChainGroups(), newChain->ChainGroupNames()) == false)
	{
		delete newChain;
		return TestUtils::TestFailed;
	}

	if (Algorithms::ValidateAllGroupsAreIndependent(newChain) == false)
	{
		delete newChain;
		return TestUtils::TestFailed;
	}

	delete newChain;
	return TestUtils::TestPassed;
}

// Create a graph and a chain with 1 group with 1 vertex in in and try to create a new group
TestUtils::TestResult FillOneGroup2VerticesWithSwitching()
{
	Graph *graph;
	graph = TestUtils::CreateGraphNOnW(7,3);
	Group group1(1);
	Group group2(2);
	bool vertexInts[] =  {0,0,1,1,0,0,1};
	VertexKey vertexName = Vertex::GetNameFromArray(vertexInts,7);
	Vertex *vertex = VertexDirectory::GetStaticCopyVertex(vertexName);
	bool vertex2Ints[] = { 1,1,0,0,0,0,1 };
	VertexKey vertex2Name = Vertex::GetNameFromArray(vertex2Ints,7);
	Vertex *vertex2 = VertexDirectory::GetStaticCopyVertex(vertex2Name);
	graph->RemoveVertex(vertex);
	group1.InsertNewVertex(vertex);
	graph->RemoveVertex(vertex2);
	group1.InsertNewVertex(vertex2);

	Chain *chain = new Chain(graph,NULL);
	chain->AddGroup(&group1);
	chain->AddGroup(&group2);

	SwitchVerticesAlgorithm algo = SwitchVerticesAlgorithm(chain);

	Chain *newChain = algo.SwitchCouples();

	Group group3(3, newChain->GetDirectory());
	newChain->AddGroup(&group3);
	SwitchVerticesAlgorithm iteration2 = SwitchVerticesAlgorithm(newChain);
	Chain *iteration2Chain = iteration2.SwitchCouples();

	map<vector<bool>, Vertex*>* vertices = VertexDirectory::GetStaticCopyVertices();
	set<int> groupNames = iteration2Chain->ChainGroupNames();
 	if (TestUtils::VerifyIsTrue(groupNames.size() == 3 ,"The group count is incorrect") == TestUtils::TestFailed)
	{
		delete newChain;
		return TestUtils::TestFailed;
	}

	Group *group = iteration2Chain->GetGroup((*groupNames.begin()));


	// check that the directory was updated correctly: All vertices in the graph appear in the graph. All vertices
	// in the group point to the right group.
	if (Algorithms::ValidateVertexDirectoryState(iteration2Chain->GetGraph(), iteration2Chain->ChainGroups(), iteration2Chain->ChainGroupNames()) == false)
	{
		delete iteration2Chain;
		delete newChain;
		return TestUtils::TestFailed;
	}

	if (Algorithms::ValidateAllGroupsAreIndependent(iteration2Chain) == false)
	{
		delete iteration2Chain;
		delete newChain;
		return TestUtils::TestFailed;
	}

	delete iteration2Chain;
	delete newChain;
	return TestUtils::TestPassed;
}

TestUtils::TestResult Run2IterationsOfSwitchingStartingFromEmpty()
{
Graph graph;
	graph = TestUtils::CreateGraph4On2(graph);

	Chain *chain = new Chain(&graph,NULL);
	Group group1(1);
	chain->AddGroup(&group1);

	SwitchVerticesAlgorithm algo = SwitchVerticesAlgorithm(chain);

	Chain *newChain = algo.SwitchSingles();
	Group group2(2);
	newChain->AddGroup(&group2);


	SwitchVerticesAlgorithm iteration2 = SwitchVerticesAlgorithm(newChain);
	Chain *iteration2Chain = iteration2.SwitchSingles();

	map<vector<bool>, Vertex*>* vertices = VertexDirectory::GetStaticCopyVertices();
	set<int> groupNames = iteration2Chain->ChainGroupNames();
	if (TestUtils::VerifyIsTrue(groupNames.size() ==2 ,"The group count is incorrect") == TestUtils::TestFailed)
	{
		delete newChain;
		return TestUtils::TestFailed;
	}

	// check that the directory was updated correctly: All vertices in the graph appear in the graph. All vertices
	// in the group point to the right group.
	if (Algorithms::ValidateVertexDirectoryState(iteration2Chain->GetGraph(), iteration2Chain->ChainGroups(),iteration2Chain->ChainGroupNames()) == false)
	{
		delete newChain;
		delete iteration2Chain;
		return TestUtils::TestFailed;
	}

	if (Algorithms::ValidateAllGroupsAreIndependent(iteration2Chain) == false)
	{
		delete newChain;
		delete iteration2Chain;
		return TestUtils::TestFailed;
	}
//	delete newChain;
	//delete iteration2Chain;
	return TestUtils::TestPassed;
}

// Run switching algorithm on full coloring
TestUtils::TestResult RunSwitchingOnFullColoring()
{
	Graph graph;
	graph = TestUtils::CreateGraph4On2(graph);
	Group group1(1);
	Group group2(2);
	Group group3(3);
	Group group4(4);

	bool vertex1Ints[] =  {0,0,1,1};
	bool vertex2Ints[] =  {1,1,0,0};
	bool vertex3Ints[] =  {0,1,1,0};
	bool vertex4Ints[] =  {1,0,0,1};
	bool vertex5Ints[] =  {1,0,1,0};
	bool vertex6Ints[] =  {0,1,0,1};

	PutVertexInGroup(vertex1Ints,&graph,&group1,4);
	PutVertexInGroup(vertex2Ints,&graph,&group1,4);
	PutVertexInGroup(vertex3Ints,&graph,&group2,4);
	PutVertexInGroup(vertex4Ints,&graph,&group2,4);
	PutVertexInGroup(vertex5Ints,&graph,&group3,4);
	PutVertexInGroup(vertex6Ints,&graph,&group3,4);

	Chain *chain = new Chain(&graph,NULL);
	chain->AddGroup(&group1);
	chain->AddGroup(&group2);
	chain->AddGroup(&group3);
	chain->AddGroup(&group4);

	SwitchVerticesAlgorithm algo = SwitchVerticesAlgorithm(chain);

	Chain *newChain = algo.SwitchSingles();
	map<vector<bool>, Vertex*>* vertices = VertexDirectory::GetStaticCopyVertices();
	set<int> groupNames = newChain->ChainGroupNames();
	if (TestUtils::VerifyIsTrue(groupNames.size() == 4 ,"The group count is incorrect") == TestUtils::TestFailed)
	{
		delete newChain;
		return TestUtils::TestFailed;
	}

	// check that the directory was updated correctly: All vertices in the graph appear in the graph. All vertices
	// in the group point to the right group.
	if (Algorithms::ValidateVertexDirectoryState(newChain->GetGraph(), newChain->ChainGroups(), newChain->ChainGroupNames()) == false)
	{
		delete newChain;
		return TestUtils::TestFailed;
	}

	if (Algorithms::ValidateAllGroupsAreIndependent(newChain) == false)
	{
		delete newChain;
		return TestUtils::TestFailed;
	}

	delete newChain;
	return TestUtils::TestPassed;
}


#endif //SWITCHINGSINGLESUNITTESTS_H